package com.hooper.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hooper.cmn.client.DictClient;
import com.hooper.hosp.enums.AuthStatusEnum;
import com.hooper.hosp.model.user.Patient;
import com.hooper.hosp.model.user.UserInfo;
import com.hooper.hosp.vo.user.LoginVo;
import com.hooper.hosp.vo.user.UserAuthVo;
import com.hooper.hosp.vo.user.UserInfoQueryVo;
import com.hooper.hospital.common.exception.HospitalException;
import com.hooper.hospital.common.helper.JwtHelper;
import com.hooper.hospital.common.utils.AuthContextHolder;
import com.hooper.user.mapper.UserMapper;
import com.hooper.user.service.PatientService;
import com.hooper.user.service.UserService;
import com.hooper.user.vo.UserVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.hooper.hospital.common.constant.HospSetConstant.VALIDATE_PHONE_PATTERN;
import static com.hooper.hospital.common.constant.UerConstant.STATUES_DISABLE;
import static com.hooper.hospital.common.constant.UerConstant.STATUES_NORMAL;
import static com.hooper.hospital.common.constant.UserConstant.*;
import static com.hooper.hospital.common.result.ResultCodeEnum.*;

/**
 * @author Tim Hooper
 * @version 1.0
 * @time 2022/10/03/14:46
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, UserInfo> implements UserService {

    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private PatientService patientService;

    @Override
    public Map<String, Object> login(LoginVo loginVo) {
        String phone = loginVo.getPhone();
        String code = loginVo.getCode();
        log.info("phone:{},code:{}",phone,code);
        //check whether the params are empty
        if (StringUtils.isAnyBlank(phone, code)) {
            throw new HospitalException(PARAM_EMPTY);
        }
        //verify the phone
        if (!Pattern.matches(VALIDATE_PHONE_PATTERN, phone)) {
            throw new HospitalException(PHONE_NOT_VALIDATE);
        }


        String redisCode = redisTemplate.opsForValue().get(phone);
        log.warn("the input code is {}", redisCode);
        //verify the code
        if (!code.equals(redisCode)) {
            throw new HospitalException(CODE_ERROR);
        }

        //绑定手机号码
        UserInfo userInfo;
        if (!StringUtils.isEmpty(loginVo.getOpenid())) {
            userInfo = this.getUserByOpenid(loginVo.getOpenid());
            if (null != userInfo) {
                userInfo.setPhone(loginVo.getPhone());
                this.updateById(userInfo);
            } else {
                throw new HospitalException(DATA_ERROR);
            }
        } else {
            //retrieve the db, check if the user has already existed
            LambdaQueryWrapper<UserInfo> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(UserInfo::getPhone, phone);
            userInfo = baseMapper.selectOne(userWrapper);
        }
        Map<String, Object> map = new HashMap<>(2);
        //if this is a new user save it to the db
        if (userInfo == null) {
            UserInfo newUser = new UserInfo();
            newUser.setPhone(phone);
            //default name would be the 用户 + their phone number
            newUser.setName("用户" + phone);
            newUser.setStatus(STATUES_NORMAL);
            baseMapper.insert(newUser);
            map.put("name", newUser.getName());
            String token = JwtHelper.createToken(newUser.getId(), newUser.getName());
            map.put("token", token);
            return map;
        } else {
            //check if the user had been banned before
            if (userInfo.getStatus() == STATUES_DISABLE) {
                throw new HospitalException(LOGIN_DISABLED_ERROR);
            }
        }

        String name = userInfo.getName();
        if (StringUtils.isEmpty(name)) {
            String nickName = userInfo.getNickName();
            name = StringUtils.isEmpty(nickName) ? userInfo.getPhone() : nickName;
        }
        map.put("name", name);
        String token = JwtHelper.createToken(userInfo.getId(), name);
        map.put("token", token);
        return map;
    }

    @Override
    public UserInfo getUserByOpenid(String openid) {
        if (StringUtils.isEmpty(openid)) {
            throw new HospitalException(PARAM_EMPTY);
        }
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserInfo::getOpenid, openid);
        return baseMapper.selectOne(wrapper);
    }

    @Override
    public void getUserAuth(UserAuthVo authVo, HttpServletRequest request) {
        if (authVo == null) {
            throw new HospitalException(PARAM_EMPTY);
        }
        //get user id through token
        Long userId = AuthContextHolder.getUserId(request);
        if (userId == null) {
            throw new HospitalException(LOGIN_REQUIRE);
        }
        //retrieve this user
        UserInfo user = this.getById(userId);
        //check if the db exists the user
        if (user == null) {
            throw new HospitalException(NO_SUCH_DATA);
        }

        user.setName(authVo.getName());
        user.setCertificatesType(authVo.getCertificatesType());
        user.setCertificatesNo(authVo.getCertificatesNo());
        user.setCertificatesUrl(authVo.getCertificatesUrl());
        user.setAuthStatus(AuthStatusEnum.AUTH_RUN.getStatus());

        this.updateById(user);

    }

    @Override
    public IPage<UserInfo> pageByConditions(int currentPage, int pageSize, UserInfoQueryVo queryVo) {
        Page<UserInfo> page = new Page<>(currentPage, pageSize);
        if (queryVo == null) {
            return this.page(page, null);
        }
        Integer status = queryVo.getStatus();
        Integer authStatus = queryVo.getAuthStatus();
        String name = queryVo.getKeyword();
        String createTimeBegin = queryVo.getCreateTimeBegin();
        String createTimeEnd = queryVo.getCreateTimeEnd();
        LambdaQueryWrapper<UserInfo> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(status != null, UserInfo::getStatus, status)
                .eq(authStatus != null, UserInfo::getAuthStatus, authStatus)
                .like(StringUtils.isNotEmpty(name), UserInfo::getName, name)
                .ge(StringUtils.isNotEmpty(createTimeBegin), UserInfo::getCreateTime, createTimeBegin)
                .le(StringUtils.isNotEmpty(createTimeEnd), UserInfo::getCreateTime, createTimeEnd);
        this.page(page, wrapper);
        return page.setRecords(
                page.getRecords().stream().peek(item -> {
                    item.getParam().put("authStatusString", AuthStatusEnum.getStatusNameByStatus(item.getAuthStatus()));
                    //处理用户状态 0  1
                    String statusString = item.getStatus() == 0 ? "锁定" : "正常";
                    item.getParam().put("statusString", statusString);
                }).collect(Collectors.toList()));
    }

    @Override
    public void lock(String id, Integer status) {
        if (StringUtils.isEmpty(id)) {
            throw new HospitalException(PARAM_EMPTY);
        }
        if (status != STATUES_NORMAL && status != STATUES_DISABLE) {
            throw new HospitalException(NO_SUCH_STATUES);
        }

        UserInfo user = baseMapper.selectById(id);
        if (user == null) {
            throw new HospitalException(NO_SUCH_DATA);
        }

        if (user.getStatus() == status.intValue()) {
            return;
        }
        user.setStatus(status);
        this.updateById(user);
    }

    @Override
    public UserVo getUserDetail(String id) {

        if (StringUtils.isEmpty(id)) {
            throw new HospitalException(PARAM_EMPTY);
        }

        UserInfo user = baseMapper.selectById(id);
        if (user == null) {
            throw new HospitalException(NO_SUCH_DATA);
        }
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);

        List<Patient> patientList = patientService.listByUserId(id);
        userVo.setPatientList(patientList);

        return userVo;
    }

    @Override
    public void approval(String userId, Integer authStatus) {
        if (StringUtils.isEmpty(userId)) {
            throw new HospitalException(PARAM_EMPTY);
        }
        if (authStatus == CERTIFYING || authStatus == CERTIFY_SUCCESS) {
            UserInfo user = baseMapper.selectById(userId);
            if (user == null) {
                throw new HospitalException(NO_SUCH_DATA);
            }
            user.setAuthStatus(authStatus);
        } else {
            throw new HospitalException(NO_SUCH_STATUES);
        }

    }
}
